Imports System.Drawing

Imports ExpertPdf.HtmlToPdf
Imports ExpertPdf.HtmlToPdf.PdfDocument

Partial Class _Default
    Inherits System.Web.UI.Page

    Private TOC_ENTRIES_COUNT As Integer = 16
    Private PAGE_NUMBER_FONT_SIZE As Integer = 10

    Protected Sub btnConvert_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnConvert.Click
        Dim pdfConverter As PdfConverter = New PdfConverter()

        ' show the bookmarks when the document is opened
        pdfConverter.PdfViewerPreferences.PageMode = ViewerPageMode.UseOutlines

        ' set top and bottom page margins
        pdfConverter.PdfDocumentOptions.TopMargin = 5
        pdfConverter.PdfDocumentOptions.BottomMargin = 5

        ' Inform the converter about the HTML elements for which we want the location in PDF
        ' In this sample we want the location of the entries in the Table of Contents
        ' The HTML ID of each entry in the table of contents is of form TOCEntry_{EntryIndex}_ID
        ' the HTML ID of each target of a table of contents entry is of form TOCEntry_{EntryIndex}_Target_ID

        ' Both toc entries and toc entries targets locations in PDF will be retrieved
        ' and therefore the number of IDs is twice TOC entries number
        Dim IDs(2 * TOC_ENTRIES_COUNT) As String
        pdfConverter.HtmlElementsMappingOptions.HtmlElementIds = IDs

        Dim mappingsTableIdx As Integer = 0
        Dim tocEntryIndex As Integer = 1
        For tocEntryIndex = 1 To TOC_ENTRIES_COUNT Step 1
            ' add the HTML ID of the TOC entry element to the list of elements for which we want the PDF location
            Dim tocEntryID As String = String.Format("TOCEntry_{0}_ID", tocEntryIndex)
            pdfConverter.HtmlElementsMappingOptions.HtmlElementIds(mappingsTableIdx) = tocEntryID
            mappingsTableIdx = mappingsTableIdx + 1

            ' add the HTML ID of the TOC entry target element to the list of elements for which we want the PDF location
            Dim tocEntryTargetID As String = String.Format("TOCEntry_{0}_Target_ID", tocEntryIndex)
            pdfConverter.HtmlElementsMappingOptions.HtmlElementIds(mappingsTableIdx) = tocEntryTargetID
            mappingsTableIdx = mappingsTableIdx + 1
        Next

        ' set bookmark options
        pdfConverter.PdfBookmarkOptions.TagNames = New String() {"A"}
        pdfConverter.PdfBookmarkOptions.ClassNameFilter = "bookmark"

        ' the URL of the HTML document to convert
        Dim thisPageURL As String = HttpContext.Current.Request.Url.AbsoluteUri
        Dim htmlBookFilePath As String = thisPageURL.Substring(0, thisPageURL.LastIndexOf("/"c)) + "/HtmlBook/Book.htm"

        ' call the converter and get a Document object from URL
        Dim pdfDocument As Document = pdfConverter.GetPdfDocumentObjectFromUrl(htmlBookFilePath)

        ' Create a font used to write the page numbers in the table of contents
        Dim pageNumberFont As PdfFont = pdfDocument.Fonts.Add(New Font("Arial", PAGE_NUMBER_FONT_SIZE, FontStyle.Bold, GraphicsUnit.Point), True)

        ' get the right edge of the table of contents where to position the page numbers
        Dim tocEntryMaxRight As Single = 0.0F
        For tocEntryIndex = 1 To TOC_ENTRIES_COUNT Step 1

            Dim tocEntryID As String = String.Format("TOCEntry_{0}_ID", tocEntryIndex)
            Dim tocEntryLocation As HtmlElementMapping = pdfConverter.HtmlElementsMappingOptions.HtmlElementsMappingResult.GetElementByHtmlId(tocEntryID)
            If tocEntryLocation.PdfRectangles(0).Rectangle.Right > tocEntryMaxRight Then
                tocEntryMaxRight = tocEntryLocation.PdfRectangles(0).Rectangle.Right
            End If
        Next


        ' Add page number for each entry in the table of contents
        Dim tocEntryIdx As Integer = 1
        For tocEntryIdx = 1 To TOC_ENTRIES_COUNT Step 1
            Dim tocEntryID As String = String.Format("TOCEntry_{0}_ID", tocEntryIdx)
            Dim tocEntryTargetID As String = String.Format("TOCEntry_{0}_Target_ID", tocEntryIdx)

            Dim tocEntryLocation As HtmlElementMapping = pdfConverter.HtmlElementsMappingOptions.HtmlElementsMappingResult.GetElementByHtmlId(tocEntryID)
            Dim tocEntryTargetLocation As HtmlElementMapping = pdfConverter.HtmlElementsMappingOptions.HtmlElementsMappingResult.GetElementByHtmlId(tocEntryTargetID)

            ' get the TOC entry page and bounds
            Dim tocEntryPdfPage As PdfPage = pdfDocument.Pages.Item(tocEntryLocation.PdfRectangles(0).PageIndex)
            Dim tocEntryPdfRectangle As RectangleF = tocEntryLocation.PdfRectangles(0).Rectangle

            ' get the page number of target where the TOC entry points
            Dim tocEntryTargetPageNumber As Integer = tocEntryTargetLocation.PdfRectangles(0).PageIndex + 1

            ' add dashed line from text entry to the page number
            Dim lineToNumber As LineElement = New LineElement(tocEntryPdfRectangle.Right + 5, tocEntryPdfRectangle.Y + tocEntryPdfRectangle.Height / 2, tocEntryMaxRight + 80, tocEntryPdfRectangle.Y + tocEntryPdfRectangle.Height / 2)
            lineToNumber.LineStyle.LineWidth = 1
            lineToNumber.LineStyle.LineDashStyle = LineDashStyle.Dash
            lineToNumber.ForeColor = Color.Green
            tocEntryPdfPage.AddElement(lineToNumber)

            ' create the page number text element to the right of the TOC entry
            Dim pageNumberTextEement As TextElement = New TextElement(tocEntryMaxRight + 85, tocEntryPdfRectangle.Y, -1, tocEntryPdfRectangle.Height, tocEntryTargetPageNumber.ToString(), pageNumberFont)
            pageNumberTextEement.TextAlign = HorizontalTextAlign.Left
            pageNumberTextEement.VerticalTextAlign = VerticalTextAlign.Middle
            pageNumberTextEement.ForeColor = Color.Blue

            ' add the page number to the right of the TOC entry
            tocEntryPdfPage.AddElement(pageNumberTextEement)
        Next

        ' Save the Document 
        Dim pdfBytes As Byte()

        Try
            pdfBytes = pdfDocument.Save()
        Finally
            ' close the Document to realease all the resources
            pdfDocument.Close()
        End Try

        ' send the PDF document as a response to the browser for download
        Dim Response As System.Web.HttpResponse = System.Web.HttpContext.Current.Response
        Response.Clear()
        Response.AddHeader("Content-Type", "binary/octet-stream")
        Response.AddHeader("Content-Disposition", "attachment; filename=ConversionResult.pdf; size=" & pdfBytes.Length.ToString())
        Response.Flush()
        Response.BinaryWrite(pdfBytes)
        Response.Flush()
        Response.End()

    End Sub

End Class
